package cn.bugstack.springframework.aop.aspectj;

import cn.bugstack.springframework.aop.ClassFilter;
import cn.bugstack.springframework.aop.MethodMatcher;
import cn.bugstack.springframework.aop.Pointcut;
import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.PointcutPrimitive;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

/**
 * PointcutPrimitive类
 * 用于表示切点原语。
 * 切点原语是一组用于定义切点的基本构建块，它们描述了在代码中需要匹配的具体操作或行为。
 * PointcutPrimitive 类定义了一系列枚举常量，每个常量代表一种切点原语，这些原语包括 AspectJ 表达式中常用的操作和行为。
 * 例如，常见的切点原语包括 execution（方法执行）、call（方法调用）、within（类内）、args（方法参数）、this（目标对象）等等。
 * AspectJ 编织器可以使用这些切点原语来构建更复杂的切点表达式，以便在代码中选择性地匹配特定的连接点，并在连接点上应用相应的切面逻辑。
 * 这些切点原语为开发者提供了灵活的工具，可以根据需要精确地定义切点，从而实现精准的横切关注点（cross-cutting concerns）的逻辑。
 */

/**
 * PointcutExpression类
 * 用于表示切点表达式。
 * 切点表达式是 AspectJ 中用于描述切点的语法，它定义了在代码中需要匹配的连接点模式。
 * PointcutExpression 类封装了 AspectJ 编译器解析和评估切点表达式的功能，可以用于检查给定的连接点是否匹配特定的切点表达式。
 * 它提供了一系列方法来处理切点表达式，包括解析表达式、匹配连接点等。
 * 通过 PointcutExpression 类，开发者可以创建和管理切点表达式，然后将其应用于代码中以选择性地匹配连接点，并在连接点上应用相应的切面逻辑。
 */

/**
 * PointcutParser类
 * 用于解析切点表达式字符串并创建相应的切点表达式对象。
 * PointcutParser 类主要负责以下功能：
 * 1、解析切点表达式：该类提供了 parsePointcutExpression 方法，接受切点表达式字符串作为参数，然后将其解析为相应的 PointcutExpression 对象。
 * 2、支持指定的切点原语和类加载器：PointcutParser 类可以根据给定的切点原语集合和类加载器来解析切点表达式。
 *    这样可以限制解析器只支持特定的切点原语，以及在解析过程中使用指定的类加载器来加载相关的类信息。
 * 3、创建切点表达式对象：通过解析切点表达式字符串，PointcutParser 类可以创建相应的 PointcutExpression 对象，表示切点表达式的语法树结构。
 */

/**
 * AspectJExpressionPointcut类
 * AspectJExpressionPointcut 是 Spring AOP 模块中的一个类，它实现了 Pointcut、ClassFilter 和 MethodMatcher 接口，
 * 用于定义切点（Pointcut）的行为。这个类允许开发者使用 AspectJ 的表达式语言来定义切点，使得 Spring AOP 能够以声明式的方式指定哪些方法应该被拦截。
 *
 * 下面是对 AspectJExpressionPointcut 类的解析：
 *
 * Pointcut 接口：Pointcut 接口是 Spring AOP 中的核心接口之一，它用于匹配连接点（Joinpoint），即程序执行过程中的特定点，比如方法执行。
 * AspectJExpressionPointcut 通过实现 Pointcut 接口，提供了基于 AspectJ 表达式匹配连接点的能力。
 *
 * ClassFilter 接口：这个接口用于测试类是否应该被包含在切点中。AspectJExpressionPointcut 实现了 ClassFilter，
 * 这意味着它可以根据 AspectJ 表达式来决定哪些类的方法应该被考虑作为连接点。
 *
 * MethodMatcher 接口：这个接口用于测试方法是否应该被包含在切点中。AspectJExpressionPointcut 实现了 MethodMatcher，
 * 这意味着它可以根据 AspectJ 表达式来匹配具体的方法。
 *
 * AspectJExpressionPointcut 使用 AspectJ 的表达式语言来定义切点，
 * 例如 "execution(* com.example.MyService.*(..))" 可以匹配 com.example.MyService 类的所有方法。
 * 这种表达式的语法非常强大，可以精确地指定想要匹配的方法，包括方法名、参数类型、返回值类型等。
 *
 * 当 Spring AOP 在运行时评估切点时，它会使用 AspectJExpressionPointcut 来检查当前的方法调用是否与定义的切点表达式匹配。
 * 如果匹配，那么与之关联的通知（Advice）就会被执行，从而实现横切关注点（Cross-Cutting Concerns）的织入。
 *
 */

public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher {

    // 支持的切点原语集合。
    private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>();

    static {
        // 初始化支持的切点原语集合，这里只支持EXECUTION原语。
        SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
    }

    // 存储解析后的切点表达式。
    private final PointcutExpression pointcutExpression;

    /**
     * 构造函数，用于创建一个AspectJ表达式切点。
     *
     * @param expression 切点表达式字符串。
     */
    public AspectJExpressionPointcut(String expression) {
        // 使用支持的切点原语和当前类的类加载器解析切点表达式。
        PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, this.getClass().getClassLoader());
        pointcutExpression = pointcutParser.parsePointcutExpression(expression);
    }

    /**
     * 判断给定的类是否匹配切点表达式。
     *
     * @param clazz 待匹配的类。
     * @return 如果类可能包含匹配的连接点，则返回true；否则返回false。
     */
    @Override
    public boolean matches(Class<?> clazz) {
        return pointcutExpression.couldMatchJoinPointsInType(clazz);
    }

    /**
     * 判断给定的方法是否匹配切点表达式。
     *
     * @param method 待匹配的方法。
     * @param targetClass 方法所在的目标类。
     * @return 如果方法执行完全匹配，则返回true；否则返回false。
     */
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return pointcutExpression.matchesMethodExecution(method).alwaysMatches();
    }

    /**
     * 获取类过滤器。
     * @return 返回此对象本身，因为本身实现了ClassFilter接口。
     */
    @Override
    public ClassFilter getClassFilter() {
        return this;
    }

    /**
     * 获取方法匹配器。
     * @return 返回此对象本身，因为本身实现了MethodMatcher接口。
     */
    @Override
    public MethodMatcher getMethodMatcher() {
        return this;
    }

}

